package com.daily.daily_push.config;

import cn.hutool.http.HttpRequest;
import com.alibaba.fastjson.JSON;
import com.daily.daily_push.vo.WxCpDefaultResult;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.RedisTemplate;

import java.util.concurrent.TimeUnit;

/**
 * @author ZhanKui
 * @date 2024/07/16
 */
@Slf4j
public class WxConfigNew {
    private static final long EXPIRATION_BUFFER = 300L; // seconds
    private static final long EXPIRATION_TIME = 2L; // hours
    private static final String LOCK_KEY = "wxAccessTokenLock";
    private static final long LOCK_EXPIRE_TIME = 30000L; // 30 seconds




    /**
     * 获取token
     * @param redisTemplateString
     * @param corpId
     * @param corpSecret
     * @return {@link WxCpDefaultResult}
     */// 配置企业微信服务
    public static WxCpDefaultResult getAccessToken(RedisTemplate<String, String> redisTemplateString, String corpId, String corpSecret) {
        int maxRetryCount = 5;
        int retryCount = 0;
        // 使用 Redis 分布式锁来处理并发问题
        while (retryCount < maxRetryCount) {
            Boolean lockAcquired = redisTemplateString.opsForValue().setIfAbsent(LOCK_KEY, "lock", LOCK_EXPIRE_TIME, TimeUnit.MILLISECONDS);
            if (Boolean.TRUE.equals(lockAcquired)) {
                try {
                    String wxAccessTokenKey = "wx" + corpId;
                    String accessToken = redisTemplateString.opsForValue().get(wxAccessTokenKey);
                    //token已存在
                    if (accessToken != null) {
                        Long expire = redisTemplateString.getExpire(wxAccessTokenKey, TimeUnit.SECONDS);
                        if (expire != null && expire > EXPIRATION_BUFFER) {
                            return WxCpDefaultResult.builder().errcode(0L).access_token(accessToken).build();
                        } else {
                            //token将要过期，重置token
                            redisTemplateString.delete(wxAccessTokenKey);
                            WxCpDefaultResult wxCpDefaultResult = fetchNewAccessToken(corpId, corpSecret);
                            if (0 == wxCpDefaultResult.errcode) {
                                redisTemplateString.opsForValue().set(wxAccessTokenKey, wxCpDefaultResult.getAccess_token(), EXPIRATION_TIME, TimeUnit.HOURS);
                                return WxCpDefaultResult.builder().errcode(0L).access_token(wxCpDefaultResult.getAccess_token()).build();
                            } else if (-1 == wxCpDefaultResult.errcode) {
                                return WxCpDefaultResult.builder().errcode(-1L).throwMsg(wxCpDefaultResult.getThrowMsg()).build();
                            } else {
                                return wxCpDefaultResult;
                            }
                        }
                    }
                    //token不存在
                    WxCpDefaultResult wxCpDefaultResult = fetchNewAccessToken(corpId, corpSecret);
                    if (0 == wxCpDefaultResult.errcode) {
                        redisTemplateString.opsForValue().set(wxAccessTokenKey, wxCpDefaultResult.getAccess_token(), EXPIRATION_TIME, TimeUnit.HOURS);
                        return WxCpDefaultResult.builder().errcode(0L).access_token(wxCpDefaultResult.getAccess_token()).build();
                    } else if (-1 == wxCpDefaultResult.errcode) {
                        return WxCpDefaultResult.builder().errcode(-1L).throwMsg(wxCpDefaultResult.getThrowMsg()).build();
                    } else {
                        return wxCpDefaultResult;
                    }
                } finally {
                    // 释放锁
                    redisTemplateString.delete(LOCK_KEY);
                }
            } else {
                retryCount++;
                // 如果未能获得锁，可以等待一段时间后重试
                try {
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }
        }
        return WxCpDefaultResult.builder().errcode(-1L).throwMsg("获取redis锁失败，请稍后重试！").build();
    }

    private static WxCpDefaultResult fetchNewAccessToken(String corpId, String corpSecret) {
        String url = String.format("https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=%s&corpsecret=%s", corpId, corpSecret);
        String res = HttpRequest.get(url).execute().body();
        log.info("企业微信获取access_token返回结果 ：{}", res);
        if (StringUtils.isNotBlank(res)) {
            WxCpDefaultResult wxCpDefaultResult = JSON.parseObject(res, WxCpDefaultResult.class);
            return wxCpDefaultResult;
        } else {
            return WxCpDefaultResult.builder().errcode(-1L).throwMsg("请求企业微信 " + url + "接口获取token失败！").build();
        }

    }

    /**
     * token失效后重置
     * @param redisTemplateString
     * @param corpId
     * @param corpSecret
     * @return {@link WxCpDefaultResult}
     */
    public static WxCpDefaultResult updateAccessToken(RedisTemplate<String, String> redisTemplateString, String corpId, String corpSecret) {
        int maxRetryCount = 5;
        int retryCount = 0;
        // 使用 Redis 分布式锁来处理并发问题
        while (retryCount < maxRetryCount) {
            Boolean lockAcquired = redisTemplateString.opsForValue().setIfAbsent(LOCK_KEY, "lock", LOCK_EXPIRE_TIME, TimeUnit.MILLISECONDS);
            if (Boolean.TRUE.equals(lockAcquired)) {
                try {
                    String wxAccessTokenKey = "wx" + corpId;
                    String accessToken = redisTemplateString.opsForValue().get(wxAccessTokenKey);
                    if (StringUtils.isNotBlank(accessToken)) {
                        redisTemplateString.delete(wxAccessTokenKey);
                        WxCpDefaultResult wxCpDefaultResult = fetchNewAccessToken(corpId, corpSecret);
                        if (0 == wxCpDefaultResult.errcode) {
                            redisTemplateString.opsForValue().set(wxAccessTokenKey, wxCpDefaultResult.getAccess_token(), EXPIRATION_TIME, TimeUnit.HOURS);
                            return WxCpDefaultResult.builder().errcode(0L).access_token(wxCpDefaultResult.getAccess_token()).build();
                        } else if (-1 == wxCpDefaultResult.errcode) {
                            return WxCpDefaultResult.builder().errcode(-1L).throwMsg(wxCpDefaultResult.getThrowMsg()).build();
                        } else {
                            return wxCpDefaultResult;
                        }
                    } else {
                        getAccessToken(redisTemplateString, corpId, corpSecret);
                    }

                } finally {
                    redisTemplateString.delete(LOCK_KEY);
                }
            } else {
                retryCount++;
                try {
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }
        }
        return WxCpDefaultResult.builder().errcode(-1L).throwMsg("获取redis锁失败，请稍后重试！").build();
    }

}
